//
// Created by SongpingWang on 2024/10/9.
//
#ifndef ZDATAFRAME_ZDATAVIEW_H
#define ZDATAFRAME_ZDATAVIEW_H

#include "ZDataBase.h"

namespace NDFrame {
    template<typename StringType, typename T>
    class ZDFrame_API ColView;

    template<typename StringType>
    class ZDFrame_API ZDataView : public ZDataBase<StringType> {
        using DataType = ZDataFrame<StringType>;
        using ItemType = DataItem<StringType>;
        using FieldInt = ColView<StringType, int>;
        using FieldStr = ColView<StringType, StringType>;
        using VecItemPtr = std::vector<DataItem<StringType> *>;
        using CharType = typename StringType::value_type;
        using RegexType = typename std::conditional<std::is_same<StringType, std::string>::value, std::regex, std::wregex>::type;
        using VecRegex = std::vector<RegexType>;

    private:
        size_t m_size;
        ItemType *m_dataPtr;

    public:
        explicit ZDataView(const DataType &dataFrame) : m_size(dataFrame.size()), m_dataPtr(dataFrame.getItemPtr()) {}

        ZDataView(const DataType &dataFrame, size_t idx0, size_t idx1) : m_size(idx1 - idx0),
                                                                         m_dataPtr(dataFrame.getItemPtr() + idx0) {
            if (idx0 >= dataFrame.size() || idx1 > dataFrame.size() || idx0 > idx1) {
                throw std::out_of_range("View range out of bounds");
            }
        }

        ZDataView(const ZDataView &dataview, size_t idx0, size_t idx1) : m_size(idx1 - idx0),
                                                                         m_dataPtr(m_dataPtr + idx0) {
            if (idx0 >= dataview.size() || idx1 > dataview.size() || idx0 > idx1) {
                throw std::out_of_range("View range out of bounds");
            }
        }

        ItemType &back() override {
            if (m_size == 0) {
                throw std::out_of_range("ZDataView is empty");
            }
            return m_dataPtr[m_size - 1];
        }

        ItemType &front() override {
            if (m_size == 0) {
                throw std::out_of_range("ZDataView is empty");
            }
            return m_dataPtr[0];
        }

        [[nodiscard]] size_t size() const override { return m_size; }

        [[nodiscard]] ItemType *getItemPtr() const override { return m_dataPtr; }

        [[nodiscard]] bool empty() const override { return m_size == 0; }

        MAYBE_USE inline static bool matches_regex(const StringType &text, const RegexType &regex_) {
            return std::regex_search(text, regex_);
        }

        ColView<StringType, int> field(int ItemType::* member) const override {
            return ColView<StringType, int>(*this, member);
        }

        ColView<StringType, StringType> field(StringType ItemType::* member) const override {
            return ColView<StringType, StringType>(*this, member);
        }

        MAYBE_USE FieldInt X0() const override { return this->field(&ItemType::x0); }

        MAYBE_USE FieldInt X1() const override { return this->field(&ItemType::x1); }

        MAYBE_USE FieldInt Y0() const override { return this->field(&ItemType::y0); }

        MAYBE_USE FieldInt Y1() const override { return this->field(&ItemType::y1); }

        MAYBE_USE FieldInt Width() const override { return this->field(&ItemType::width); }

        MAYBE_USE FieldInt Height() const override { return this->field(&ItemType::height); }

        MAYBE_USE FieldStr Text() const override { return this->field(&ItemType::text); }

        MAYBE_USE FieldStr Text_sep() const override { return this->field(&ItemType::text_sep); }

        VOID_USE void print() const override {
            ZDataBase<StringType>::print_data(*this);
        }

        const ItemType &operator[](size_t index) const {
            if (index >= m_size) {
                throw std::out_of_range("Index out of range");
            }
            return m_dataPtr[index];
        }


        /*
        *   判断ZDataFrame的text字段是否在field字符串集合中
        *   - 返回值：
        *     std::vector<size_t>& indices     返回符合条件的索引
        *     VecItemPtr& pointers 返回符合条件的ZDataFrame的行指针
        *     ZDataFrame& dataframe            返回符合条件的ZDataFrame(深复制)
        */
        bool isin(const std::vector<StringType> &field, std::vector<size_t> &out_indices) const override{
            out_indices.clear();
            for (size_t i = 0; i < m_size; ++i) {
                if (std::find(field.begin(), field.end(), m_dataPtr[i].text) != field.end()) {
                    out_indices.push_back(m_dataPtr[i].idx);
                }
            }
            return !out_indices.empty();
        }

        bool isin(const std::vector<StringType> &field, VecItemPtr &out_pointers) const override {
            out_pointers.clear();
            for (size_t i = 0; i < m_size; ++i) {
                if (std::find(field.begin(), field.end(), m_dataPtr[i].text) != field.end()) {
                    out_pointers.push_back(&m_dataPtr[i]);
                }
            }
            return !out_pointers.empty();
        }

        bool isin(const std::vector<StringType> &field, DataType &out_dataframe) const;

        /*
        * 仿照python的join函数
        * 默认为空字符串
        * join_replace对ZDataFrame的text合并后的字符串中的字符进行替换
        * const StringType& Char_为分隔符
        */
        MAYBE_USE StringType join(Field field_, const StringType &Char_ = StringType()) const;

        MAYBE_USE StringType join_replace(Field field_,
                                          CharType oldChar,
                                          const StringType& newChar) const override {
            if (this->empty() || static_cast<int>(this->size()) < 2 || newChar.size() >= 2) {
                return {};
            }
            std::function<const StringType &(const ItemType &)> getField;
            if (field_ == Field::TEXT) {
                getField = [](const ItemType &item) -> const StringType & { return item.text; };
            } else if (field_ == Field::TEXT_SEP) {
                getField = [](const ItemType &item) -> const StringType & { return item.text_sep; };
            }

            std::basic_ostringstream<CharType> oss;
            for (size_t i = 0; i < m_size; ++i) {
                for (auto c: getField(m_dataPtr[i])) {
                    if (c == oldChar) {
                        oss << newChar.c_str();
                    } else {
                        oss << c;
                    }
                }
            }
            return oss.str();
        }

        MAYBE_USE StringType join_replace(Field field_,
                                          CharType oldChar,
                                          CharType newChar,
                                          const StringType &Char_ = StringType()) const;

        MAYBE_USE StringType join_replace2(Field field_,
                                           CharType oldChar0,
                                           CharType newChar0,
                                           CharType oldChar1,
                                           CharType newChar1,
                                           const StringType &Char_ = StringType()) const;

        MAYBE_USE bool filter(const std::function<bool(const ItemType &)> &predicate, VecItemPtr &out_pointers) const;

        MAYBE_USE DataType DF_filter(const std::function<bool(const ItemType &)> &predicate) const;

        MAYBE_USE DataType DF_indices_to_df(const std::vector<size_t> &indices) const;

        MAYBE_USE DataType DF_pointers_to_df(const VecItemPtr &pointers) const;


        MAYBE_USE DataType DF_loc_regex(Field field, const RegexType &regex_) const {
            return DF_reg_impl(field, VecRegex{regex_});
        }

        MAYBE_USE DataType DF_loc_regex(Field field, const VecRegex &regex_) const {
            return DF_reg_impl(field, regex_);
        }

        //////////////////////////////////////////////

        MAYBE_USE DataType DF_loc_regex_grate_strlen(Field field, const RegexType &regex_, int len) const {
            return DF_reg_common4(field, VecRegex{regex_}, len, std::greater<>());
        }

        MAYBE_USE DataType DF_loc_regex_equal_strlen(Field field, const RegexType &regex_, int len) const {
            return DF_reg_common4(field, VecRegex{regex_}, len, std::equal_to<>());
        }

        MAYBE_USE DataType DF_loc_regex_less_strlen(Field field, const RegexType &regex_, int len) const {
            return DF_reg_common4(field, VecRegex{regex_}, len, std::less<>());
        }

        MAYBE_USE DataType DF_loc_regex_grate_strlen(Field field, const VecRegex &regex_, int len) const {
            return DF_reg_common4(field, regex_, len, std::greater<>());
        }

        MAYBE_USE DataType DF_loc_regex_equal_strlen(Field field, const VecRegex &regex_, int len) const {
            return DF_reg_common4(field, regex_, len, std::equal_to<>());
        }

        MAYBE_USE DataType DF_loc_regex_less_strlen(Field field, const VecRegex &regex_, int len) const {
            return DF_reg_common4(field, regex_, len, std::less<>());
        }

        ////////////////////////////////////////////////////////////
        MAYBE_USE DataType
        DF_loc_regex_xyxy(Field field, const RegexType &regex_, int x0, int y0, int x1, int y1) const {
            auto condition = [x0, y0, x1, y1](const ItemType &item) {
                return item.x0 > x0 && item.x1 < x1 && item.y0 > y0 && item.y1 < y1;
            };
            return DF_reg_common3(field, VecRegex{regex_}, condition);
        }

        MAYBE_USE DataType DF_loc_regex_x0x1(Field field, const RegexType &regex_, int x0, int x1) const {
            return DF_reg_common3(field, VecRegex{regex_},
                                  [x0, x1](const ItemType &item) { return item.x0 > x0 && item.x1 < x1; });
        }

        MAYBE_USE DataType DF_loc_regex_y0y1(Field field, const RegexType &regex_, int y0, int y1) const {
            return DF_reg_common3(field, VecRegex{regex_},
                                  [y0, y1](const ItemType &item) { return item.y0 > y0 && item.y1 < y1; });
        }

        MAYBE_USE DataType DF_loc_regex_x0y0(Field field, const RegexType &regex_, int x0, int y0) const {
            return DF_reg_common3(field, VecRegex{regex_},
                                  [x0, y0](const ItemType &item) { return item.x0 > x0 && item.y0 > y0; });
        }

        MAYBE_USE DataType DF_loc_regex_x1y1(Field field, const RegexType &regex_, int x1, int y1) const {
            return DF_reg_common3(field, VecRegex{regex_},
                                  [x1, y1](const ItemType &item) { return item.x1 < x1 && item.y1 < y1; });
        }

        ////////////////////////////////////////////////////////////
        MAYBE_USE DataType DF_loc_regex_x0x1(Field field, const VecRegex &regex_, int x0, int x1) const {
            return DF_reg_common3(field, regex_,
                                  [x0, x1](const ItemType &item) { return item.x0 > x0 && item.x1 < x1; });
        }

        MAYBE_USE DataType DF_loc_regex_y0y1(Field field, const VecRegex &regex_, int y0, int y1) const {
            return DF_reg_common3(field, regex_,
                                  [y0, y1](const ItemType &item) { return item.y0 > y0 && item.y1 < y1; });
        }

        MAYBE_USE DataType DF_loc_regex_x0y0(Field field, const VecRegex &regex_, int x0, int y0) const {
            return DF_reg_common3(field, regex_,
                                  [x0, y0](const ItemType &item) { return item.x0 > x0 && item.y0 > y0; });
        }

        MAYBE_USE DataType DF_loc_regex_x1y1(Field field, const VecRegex &regex_, int x1, int y1) const {
            return DF_reg_common3(field, regex_,
                                  [x1, y1](const ItemType &item) { return item.x1 < x1 && item.y1 < y1; });
        }

        MAYBE_USE DataType DF_loc_xyxy(int x0, int y0, int x1, int y1) const {
            auto condition = [x0, y0, x1, y1](const ItemType &item) -> bool {
                return item.x0 > x0 && item.y0 > y0 && item.x1 < x1 && item.y1 < y1;
            };
            return DF_xyxy_impl(condition);
        }

        MAYBE_USE DataType DF_loc_x0x1(int x0, int x1) const {
            return DF_xyxy_impl([x0, x1](const ItemType &item) { return item.x0 > x0 && item.x1 < x1; });
        }

        MAYBE_USE DataType DF_loc_y0y1(int y0, int y1) const {
            return DF_xyxy_impl([y0, y1](const ItemType &item) { return item.y0 > y0 && item.y1 < y1; });
        }

        MAYBE_USE DataType DF_loc_x0y0(int x0, int y0) const {
            return DF_xyxy_impl([x0, y0](const ItemType &item) { return item.x0 > x0 && item.y0 > y0; });
        }

        MAYBE_USE DataType DF_loc_x1y1(int x1, int y1) const {
            return DF_xyxy_impl([x1, y1](const ItemType &item) { return item.x1 < x1 && item.y1 < y1; });
        }

        MAYBE_USE DataType DF_loc_x0(int x0) const {
            return DF_xyxy_impl([x0](const ItemType &item) { return item.x0 > x0; });
        }

        MAYBE_USE DataType DF_loc_y0(int y0) const {
            return DF_xyxy_impl([y0](const ItemType &item) { return item.y0 > y0; });
        }

        MAYBE_USE DataType DF_loc_x1(int x1) const {
            return DF_xyxy_impl([x1](const ItemType &item) { return item.x1 < x1; });
        }

        MAYBE_USE DataType DF_loc_y1(int y1) const {
            return DF_xyxy_impl([y1](const ItemType &item) { return item.y1 < y1; });
        }


        /*
         * 对视图类再次筛选，函数功能与ZDataFrame一样
         * 对ZDataView进行再次过滤（具体过滤函数：传入Field：（TEXT,TEXT_SEP）, 以及筛选条件） 返回符合条件的地址
         * loc_regex             返回查找值是否为空, 第一个参数为筛选输出【ItemType的地址】
         * loc_[regex,_xyxy]     返回查找值是否为空, 第一个参数为筛选输出【ItemType的地址】,筛选条件[regex, (>x0,y0; <x1,y1)]
         * loc_[regex,_x0x1]     返回查找值是否为空, 第一个参数为筛选输出【ItemType的地址】,筛选条件[regex, (>x0; <x1)]
         * loc_[regex,_y0y1]     返回查找值是否为空, 第一个参数为筛选输出【ItemType的地址】,筛选条件[regex, (>y0; <y1)]
         * loc_[regex,_x0y0]     返回查找值是否为空, 第一个参数为筛选输出【ItemType的地址】,筛选条件[regex, (<x0; <y0)]
         * loc_[regex,_x1y1]     返回查找值是否为空, 第一个参数为筛选输出【ItemType的地址】,筛选条件[regex, (>x1; >y1)]
         */
        MAYBE_USE bool loc2_regex(VecItemPtr &out_ptr, Field field, const RegexType &regex_) const {
            return ptr2_reg_impl(out_ptr, field, VecRegex{regex_});
        }

        MAYBE_USE bool loc2_regex(VecItemPtr &out_ptr, Field field, const VecRegex &regex_) const {
            return ptr2_reg_impl(out_ptr, field, regex_);
        }


        MAYBE_USE bool
        loc2_regex_grate_strlen(VecItemPtr &out_ptr, Field field, const RegexType &regex_, int len) const {
            return ptr2_reg_common5(out_ptr, field, VecRegex{regex_}, len, std::greater<>());
        }

        MAYBE_USE bool
        loc2_regex_equal_strlen(VecItemPtr &out_ptr, Field field, const RegexType &regex_, int len) const {
            return ptr2_reg_common5(out_ptr, field, VecRegex{regex_}, len, std::equal_to<>());
        }

        MAYBE_USE bool
        loc2_regex_less_strlen(VecItemPtr &out_ptr, Field field, const RegexType &regex_, int len) const {
            return ptr2_reg_common5(out_ptr, field, VecRegex{regex_}, len, std::less<>());
        }

        MAYBE_USE bool
        loc2_regex_grate_strlen(VecItemPtr &out_ptr, Field field, const VecRegex &regex_, int len) const {
            return ptr2_reg_common5(out_ptr, field, regex_, len, std::greater<>());
        }

        MAYBE_USE bool
        loc2_regex_equal_strlen(VecItemPtr &out_ptr, Field field, const VecRegex &regex_, int len) const {
            return ptr2_reg_common5(out_ptr, field, regex_, len, std::equal_to<>());
        }

        MAYBE_USE bool
        loc2_regex_less_strlen(VecItemPtr &out_ptr, Field field, const VecRegex &regex_, int len) const {
            return ptr2_reg_common5(out_ptr, field, regex_, len, std::less<>());
        }


        MAYBE_USE bool
        loc2_regex_xyxy(VecItemPtr &out_ptr, Field field, const RegexType &regex_, int x0, int y0, int x1,
                        int y1) const {
            return ptr2_reg_common4(out_ptr, field, VecRegex{regex_},
                                    [x0, y0, x1, y1](const ItemType &item) {
                                        return item.x0 > x0 && item.x1 < x1 && item.y0 > y0 && item.y1 < y1;
                                    });
        }

        MAYBE_USE bool
        loc2_regex_x0x1(VecItemPtr &out_ptr, Field field, const RegexType &regex_, int x0, int x1) const {
            return ptr2_reg_common4(out_ptr, field, VecRegex{regex_},
                                    [x0, x1](const ItemType &item) { return item.x0 > x0 && item.x1 < x1; });
        }

        MAYBE_USE bool
        loc2_regex_y0y1(VecItemPtr &out_ptr, Field field, const RegexType &regex_, int y0, int y1) const {
            return ptr2_reg_common4(out_ptr, field, VecRegex{regex_},
                                    [y0, y1](const ItemType &item) { return item.y0 > y0 && item.y1 < y1; });
        }

        MAYBE_USE bool
        loc2_regex_x0y0(VecItemPtr &out_ptr, Field field, const RegexType &regex_, int x0, int y0) const {
            return ptr2_reg_common4(out_ptr, field, VecRegex{regex_},
                                    [x0, y0](const ItemType &item) { return item.x0 > x0 && item.y0 > y0; });
        }

        MAYBE_USE bool
        loc2_regex_x1y1(VecItemPtr &out_ptr, Field field, const RegexType &regex_, int x1, int y1) const {
            return ptr2_reg_common4(out_ptr, field, VecRegex{regex_},
                                    [x1, y1](const ItemType &item) { return item.x1 < x1 && item.y1 < y1; });
        }


        MAYBE_USE bool
        loc2_regex_x0x1(VecItemPtr &out_ptr, Field field, const VecRegex &regex_, int x0, int x1) const {
            return ptr2_reg_common4(out_ptr, field, regex_,
                                    [x0, x1](const ItemType &item) { return item.x0 > x0 && item.x1 < x1; });
        }

        MAYBE_USE bool
        loc2_regex_y0y1(VecItemPtr &out_ptr, Field field, const VecRegex &regex_, int y0, int y1) const {
            return ptr2_reg_common4(out_ptr, field, regex_,
                                    [y0, y1](const ItemType &item) { return item.y0 > y0 && item.y1 < y1; });
        }

        MAYBE_USE bool
        loc2_regex_x0y0(VecItemPtr &out_ptr, Field field, const VecRegex &regex_, int x0, int y0) const {
            return ptr2_reg_common4(out_ptr, field, regex_,
                                    [x0, y0](const ItemType &item) { return item.x0 > x0 && item.y0 > y0; });
        }

        MAYBE_USE bool
        loc2_regex_x1y1(VecItemPtr &out_ptr, Field field, const VecRegex &regex_, int x1, int y1) const {
            return ptr2_reg_common4(out_ptr, field, regex_,
                                    [x1, y1](const ItemType &item) { return item.x1 < x1 && item.y1 < y1; });
        }


        MAYBE_USE bool loc2_xyxy(VecItemPtr &out_ptr, int x0, int y0, int x1, int y1) const {
            auto condition = [x0, y0, x1, y1](const ItemType &item) {
                return item.x0 > x0 && item.y0 > y0 && item.x1 < x1 && item.y1 < y1;
            };
            return ptr2_xyxy(out_ptr, condition);
        }

        MAYBE_USE bool loc2_x0x1(VecItemPtr &out_ptr, int x0, int x1) const {
            return ptr2_xyxy(out_ptr, [x0, x1](const ItemType &item) {
                return item.x0 > x0 && item.x1 < x1;
            });
        }

        MAYBE_USE bool loc2_y0y1(VecItemPtr &out_ptr, int y0, int y1) const {
            return ptr2_xyxy(out_ptr, [y0, y1](const ItemType &item) {
                return item.y0 > y0 && item.y1 < y1;
            });
        }

        MAYBE_USE bool loc2_x0y0(VecItemPtr &out_ptr, int x0, int y0) const {
            return ptr2_xyxy(out_ptr, [x0, y0](const ItemType &item) {
                return item.x0 > x0 && item.y0 > y0;
            });
        }

        MAYBE_USE bool loc2_x1y1(VecItemPtr &out_ptr, int x1, int y1) const {
            return ptr2_xyxy(out_ptr, [x1, y1](const ItemType &item) {
                return item.x1 < x1 && item.y1 < y1;
            });
        }

        MAYBE_USE bool loc2_x0(VecItemPtr &out_ptr, int x0) const {
            return ptr2_xyxy(out_ptr, [x0](const ItemType &item) { return item.x0 < x0; });
        }

        MAYBE_USE bool loc2_y0(VecItemPtr &out_ptr, int y0) const {
            return ptr2_xyxy(out_ptr, [y0](const ItemType &item) { return item.y0 < y0; });
        }

        MAYBE_USE bool loc2_x1(VecItemPtr &out_ptr, int x1) const {
            return ptr2_xyxy(out_ptr, [x1](const ItemType &item) { return item.x1 > x1; });
        }

        MAYBE_USE bool loc2_y1(VecItemPtr &out_ptr, int y1) const {
            return ptr2_xyxy(out_ptr, [y1](const ItemType &item) { return item.y1 > y1; });
        }

        /*
        * 对视图类 ZDataView 进行二次过滤
        * - 输入 Field field_
        * - 输入 const std::vector<RegexType>& regex_, int x0, int y0, int x1, int y1
        * - 返回值：ZDataView
        */
        MAYBE_USE ZDataView DV_loc2_regex(Field field, const VecRegex &regex_) const {
            return dv2_reg_impl(field, regex_);
        }

        MAYBE_USE ZDataView DV_loc2_regex(Field field, const RegexType &regex_) const {
            return dv2_reg_impl(field, VecRegex{regex_});
        }


        MAYBE_USE ZDataView DV_loc2_regex_grate_strlen(Field field, const VecRegex &regex_, int len) const {
            return dv2_reg_common4(field, regex_, len, std::greater<>());
        }

        MAYBE_USE ZDataView DV_loc2_regex_equal_strlen(Field field, const VecRegex &regex_, int len) const {
            return dv2_reg_common4(field, regex_, len, std::equal_to<>());
        }

        MAYBE_USE ZDataView DV_loc2_regex_less_strlen(Field field, const VecRegex &regex_, int len) const {
            return dv2_reg_common4(field, regex_, len, std::less<>());
        }

        MAYBE_USE ZDataView DV_loc2_regex_grate_strlen(Field field, const RegexType &regex_, int len) const {
            return dv2_reg_common4(field, VecRegex{regex_}, len, std::greater<>());
        }

        MAYBE_USE ZDataView DV_loc2_regex_equal_strlen(Field field, const RegexType &regex_, int len) const {
            return dv2_reg_common4(field, VecRegex{regex_}, len, std::equal_to<>());
        }

        MAYBE_USE ZDataView DV_loc2_regex_less_strlen(Field field, const RegexType &regex_, int len) const {
            return dv2_reg_common4(field, VecRegex{regex_}, len, std::less<>());
        }


        MAYBE_USE ZDataView
        DV_loc2_regex_x0y0x1y1(Field field, const VecRegex &regex_, int x0, int y0, int x1, int y1) const {
            return dv2_reg_common3(field, regex_,
                                   [x0, y0, x1, y1](const ItemType &item) {
                                       return item.x0 > x0 && item.x1 < x1 && item.y0 > y0 && item.y1 < y1;
                                   });
        }

        MAYBE_USE ZDataView DV_loc2_regex_x0x1(Field field, const VecRegex &regex_, int x0, int x1) const {
            return dv2_reg_common3(field, regex_,
                                   [x0, x1](const ItemType &item) { return item.x0 > x0 && item.x1 < x1; });
        }

        MAYBE_USE ZDataView DV_loc2_regex_y0y1(Field field, const VecRegex &regex_, int y0, int y1) const {
            return dv2_reg_common3(field, regex_,
                                   [y0, y1](const ItemType &item) { return item.y0 > y0 && item.y1 < y1; });
        }

        MAYBE_USE ZDataView DV_loc2_regex_x0y0(Field field, const VecRegex &regex_, int x0, int y0) const {
            return dv2_reg_common3(field, regex_,
                                   [x0, y0](const ItemType &item) { return item.x0 > x0 && item.y0 > y0; });
        }

        MAYBE_USE ZDataView DV_loc2_regex_x1y1(Field field, const VecRegex &regex_, int x1, int y1) const {
            return dv2_reg_common3(field, regex_,
                                   [x1, y1](const ItemType &item) { return item.x1 < x1 && item.y1 < y1; });
        }

        MAYBE_USE ZDataView DV_loc2_regex_x0x1(Field field, const RegexType &regex_, int x0, int x1) const {
            return dv2_reg_common3(field, VecRegex{regex_},
                                   [x0, x1](const ItemType &item) { return item.x0 > x0 && item.x1 < x1; });
        }

        MAYBE_USE ZDataView DV_loc2_regex_y0y1(Field field, const RegexType &regex_, int y0, int y1) const {
            return dv2_reg_common3(field, VecRegex{regex_},
                                   [y0, y1](const ItemType &item) { return item.y0 > y0 && item.y1 < y1; });
        }

        MAYBE_USE ZDataView DV_loc2_regex_x0y0(Field field, const RegexType &regex_, int x0, int y0) const {
            return dv2_reg_common3(field, VecRegex{regex_},
                                   [x0, y0](const ItemType &item) { return item.x0 > x0 && item.y0 > y0; });
        }

        MAYBE_USE ZDataView DV_loc2_regex_x1y1(Field field, const RegexType &regex_, int x1, int y1) const {
            return dv2_reg_common3(field, VecRegex{regex_},
                                   [x1, y1](const ItemType &item) { return item.x1 < x1 && item.y1 < y1; });
        }


        MAYBE_USE ZDataView DV_loc2_xyxy(int x0, int y0, int x1, int y1) const {
            auto condition = [x0, y0, x1, y1](const ItemType &item) {
                return item.x0 > x0 && item.y0 > y0 && item.x1 < x1 && item.y1 < y1;
            };
            return dv2_loc(condition);
        }

        MAYBE_USE ZDataView DV_loc2_x0x1(int x0, int x1) const {
            return dv2_loc([x0, x1](const ItemType &item) {
                return item.x0 > x0 && item.x1 < x1;
            });
        }

        MAYBE_USE ZDataView DV_loc2_y0y1(int y0, int y1) const {
            return dv2_loc([y0, y1](const ItemType &item) {
                return item.y0 > y0 && item.y1 < y1;
            });
        }

        MAYBE_USE ZDataView DV_loc2_x0y0(int x0, int y0) const {
            return dv2_loc([x0, y0](const ItemType &item) {
                return item.x0 > x0 && item.y0 > y0;
            });
        }

        MAYBE_USE ZDataView DV_loc2_x1y1(int x1, int y1) const {
            return dv2_loc([x1, y1](const ItemType &item) {
                return item.x1 < x1 && item.y1 < y1;
            });
        }

        MAYBE_USE ZDataView DV_loc2_x0(int x0) const {
            return dv2_loc([x0](const ItemType &item) { return item.x0 < x0; });
        }

        MAYBE_USE ZDataView DV_loc2_y0(int y0) const {
            return dv2_loc([y0](const ItemType &item) { return item.y0 < y0; });
        }

        MAYBE_USE ZDataView DV_loc2_x1(int x1) const {
            return dv2_loc([x1](const ItemType &item) { return item.x1 > x1; });
        }

        MAYBE_USE ZDataView DV_loc2_y1(int y1) const {
            return dv2_loc([y1](const ItemType &item) { return item.y1 > y1; });
        }


    private:


        DataType DF_reg_impl(NDFrame::Field field, const VecRegex &regex_) const;

        DataType DF_xyxy_impl(const std::function<bool(const ItemType &)> & condition) const;

        DataType DF_reg_common4(
                Field field,
                const VecRegex &regex_, int len,
                const std::function<bool(size_t, size_t)> &compare) const;

        DataType DF_reg_common3(
                NDFrame::Field field,
                const VecRegex &regex_,
                const std::function<bool(const ItemType &)> &condition) const;

        bool ptr2_reg_impl(VecItemPtr &out_ptr, Field field, const VecRegex &regex_) const;

        bool ptr2_reg_common5(
                VecItemPtr &out_ptr,
                Field field,
                const VecRegex &regex_, int len,
                const std::function<bool(size_t, size_t)> &compare) const;

        bool ptr2_reg_common4(
                VecItemPtr &out_ptr,
                NDFrame::Field field,
                const RegexType &regex_,
                const std::function<bool(const ItemType &)> &condition) const;

        bool ptr2_xyxy(VecItemPtr &out_ptr, const std::function<bool(const ItemType &)> &condition) const;

        ZDataView dv2_reg_impl(Field field, const VecRegex &regex_) const;

        ZDataView dv2_reg_common4(
                NDFrame::Field field,
                const VecRegex &regex_, int len,
                const std::function<bool(size_t, size_t)> &compare) const;

        ZDataView dv2_reg_common3(
                NDFrame::Field field,
                const VecRegex &regex_,
                const std::function<bool(const ItemType &)> &condition) const;


        template<typename DVConditionIdx>
        ZDataView dv2_loc(DVConditionIdx conditionIdx) const;
    };

} // NDFrame
#include "ZDataView.inl"
#endif //ZDATAFRAME_ZDATAVIEW_H
